package com.ap.core.jbehave.submitrtp;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import java.math.BigDecimal;

import org.hamcrest.CoreMatchers;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ap.core.cxf.jaxb.common.APCORE1FaultDetailsType;
import com.ap.core.cxf.jaxb.common.DeliveryType;
import com.ap.core.cxf.jaxb.managertp.SubmitRTP1Request;
import com.ap.core.cxf.jaxb.managertp.SubmitRTP1Response;
import com.ap.core.cxf.jaxb.managertp.SubmitRTPMessageType;
import com.ap.core.cxf.jaxb.msghdr.MessageType;
import com.ap.core.cxf.jaxb.rtp.TransactionCheckOutType;
import com.ap.core.jbehave.BaseTransitionRTPSteps;
import com.ap.core.jbehave.StoryContext;
import com.ap.core.util.JaxbUtil;
import com.ap.core.util.Nullable;
import com.ap.core.util.TypedKey;
import com.core.ap.wsdl.managertpservice_1.ManageRTP1PortType;
import com.core.ap.wsdl.managertpservice_1.SubmitRTP1Fault;

public class SubmitRTPForBRNFaultSteps extends BaseTransitionRTPSteps {
	
	public static final TypedKey<Nullable<String>> brn = new TypedKey<>("BRN");
	public static final TypedKey<Nullable<MessageType>> messageType = new TypedKey<>("MessageType");
	public static final TypedKey<SubmitRTP1Request> REQUEST_TYPE = new TypedKey<>("Request Type");
	public static final TypedKey<SubmitRTP1Response> RESPONSE_TYPE = new TypedKey<>("Response Type");

	private static final Logger LOG = LoggerFactory.getLogger(SubmitRTPForBRNFaultSteps.class);

	public SubmitRTPForBRNFaultSteps(StoryContext storyContext) {
		super(storyContext);
	}

	@Given("The Consumer chosen to pay by Zapp Online AND sent some invalidate information for BRN")
	public void givenConsumerAuthoriseThePayment() {
		LOG.info("Given The Consumer chosen to pay by Zapp Online AND sent some invalidate information for BRN");
	}

	@When("The Distributor submits erroneous info to the AP server w.r.t BRN journey")
	public void whenASubmitRTPRequestisMade() throws Exception {

		final ManageRTP1PortType manageRTP1PortType = factory.getBean(ManageRTP1PortType.class);
		
		
		//Disable temporarily the Distributor is Active Will be enabled later. 
        
		
		// Testcase for Distributor is not active.
		/* 
		SubmitRTP1Request submitRTPRequest4 = generateSubmitRTPRequest(
															MessageType.SUBMITRTPFORBRN, "000005", "000001",
															TransactionCheckOutType.NRMLCHK, new BigDecimal(1.0), true,
															false);
         checkFault(new TypedKey<SubmitRTP1Fault>("DISTACTFAULT"), manageRTP1PortType,	submitRTPRequest4);															
		*/
		
		// Testcase for The amount is zero or negative
		SubmitRTP1Request submitRTPRequest2 = generateSubmitRTPRequest(
				SubmitRTPMessageType.SUBMITRTPFORBRN, "000001", "000001",
												TransactionCheckOutType.NRMLCHK, new BigDecimal(0), true, false);

		checkFault(new TypedKey<SubmitRTP1Fault>("TOTALAMOUNTFAULT"),manageRTP1PortType, submitRTPRequest2);

		// Testcase for Distributor is not registered.
		SubmitRTP1Request submitRTPRequest3 = generateSubmitRTPRequest(
				SubmitRTPMessageType.SUBMITRTPFORBRN, "990001", "000001",
													TransactionCheckOutType.NRMLCHK, new BigDecimal(1.0), true,
													false);

		checkFault(new TypedKey<SubmitRTP1Fault>("DISTREGSTFAULT"),	manageRTP1PortType, submitRTPRequest3);

		// Testcase for Merchant is not associated with the distributor.
		SubmitRTP1Request submitRTPRequest5 = generateSubmitRTPRequest(
				SubmitRTPMessageType.SUBMITRTPFORBRN, "000001", "990001",
													TransactionCheckOutType.NRMLCHK, new BigDecimal(1.0), true,
													false);

		checkFault(new TypedKey<SubmitRTP1Fault>("MERDISTASSOCFAULT"),	manageRTP1PortType, submitRTPRequest5);

		// Testcase for Delivery Information is required
		SubmitRTP1Request submitRTPRequest7 = generateSubmitRTPRequest(
				SubmitRTPMessageType.SUBMITRTPFORBRN, "000001", "000001",
													TransactionCheckOutType.NRMLCHK, new BigDecimal(1.0), false,
													false);

		checkFault(new TypedKey<SubmitRTP1Fault>("DELINFOFAULT"), manageRTP1PortType, submitRTPRequest7);

		// Testcase for Delivery Address is required.
		SubmitRTP1Request submitRTPRequest8 = generateSubmitRTPRequest(
				SubmitRTPMessageType.SUBMITRTPFORBRN, "000001", "000001",
													TransactionCheckOutType.NRMLCHK, new BigDecimal(1.0), true,
													true);

		checkFault(new TypedKey<SubmitRTP1Fault>("DELADDRFAULT"), manageRTP1PortType, submitRTPRequest8);

		LOG.info("When -  Response Received");

	}

	private void checkFault(TypedKey<SubmitRTP1Fault> FAULT,
			final ManageRTP1PortType singnedPort,
			SubmitRTP1Request submitRTPRequest1) {
		try {
			singnedPort.submitRTP1(submitRTPRequest1);
		} catch (SubmitRTP1Fault fault) {
			storyContext.put(FAULT, fault);
		}
	}

	private SubmitRTP1Request generateSubmitRTPRequest(SubmitRTPMessageType messageType,
			String distributorId, String merchantId,
			TransactionCheckOutType transactionCheckOutType,
			BigDecimal totalPaymentReqAmount, boolean isDeliveryRequired,
			boolean isDeliveryAddressRequired) {
		SubmitRTP1Request submitRTPRequest = createSubmitRTPRequest(messageType);

		submitRTPRequest.getRTPSenderInfo().getDistributorInfo()
				.setDistributorId(distributorId);
		submitRTPRequest.getRTPSenderInfo().getDetailMerchantInfo()
				.getMerchantInfo().setMerchantId(merchantId);
		submitRTPRequest.getRTPSummary().setTxCheckout(transactionCheckOutType);
		submitRTPRequest.getRTPSummary().getPaymtAmtInfo()
				.setTotalPaymentReqAmount(totalPaymentReqAmount);

		if (submitRTPRequest.getDelivery().getDeliveryType() == DeliveryType.DIGDEL
				|| isDeliveryRequired) {

			if (isDeliveryAddressRequired) {
				submitRTPRequest.getDelivery().setDeliveryType(
						DeliveryType.COLLST);
			}

			submitRTPRequest.getDelivery().setDeliveryAddress(null);
		}

		if (!isDeliveryRequired) {
			submitRTPRequest.setDelivery(null);
		}

		LOG.info("When -  The Distributor submits erroneous info to the AP server w.r.t BRN journey");
		JaxbUtil.newInstance().javaToXML(SubmitRTP1Request.class, submitRTPRequest);
		return submitRTPRequest;
	}

	@Then("The AP Server should send the appropriate BRN journey fault information back to OSB")
	public void thenResponseWasReceivedWithBRN() {

		LOG.info("Then - The AP Server should send the appropriate BRN journey fault information back to OSB");

		for (TypedKey<SubmitRTP1Fault> key : storyContext.keySet()) {
			APCORE1FaultDetailsType fault = storyContext.get(key).getFaultInfo();		
			StringBuilder stringBuilder = new StringBuilder(150);
	    	stringBuilder.append("\n FaultString:"+fault.toString());
	    	stringBuilder.append(" FaultId:"+fault.getFaultid());
	    	stringBuilder.append("\n"+" Errorcode:"+fault.getErrorcode());
	        stringBuilder.append( " ErrorMessage:"+fault.getErrormessage());
	        stringBuilder.append("\n"+" InternalErrorCode:"+fault.getInternalcode());
	        stringBuilder.append(" InternalErrorMessage:"+fault.getInternalmessage());
	        String message = stringBuilder.toString();
			LOG.info("\n\nFault Error Details for "	+key+ " :"+ message+"\n");
			JaxbUtil.newInstance().javaToXML(APCORE1FaultDetailsType.class, fault);
			
	        assertThat("Fault Id is not as expected", false, CoreMatchers.is(equalTo(fault.getFaultid() == null)));
	        assertThat("Error code is not as expected",	false,	CoreMatchers.is(equalTo(fault.getErrorcode() == null)));
	        assertThat("Error Message is not as expected", false, CoreMatchers.is(equalTo(fault.getErrormessage() == null)));
	        assertThat("Internal Code is not as expected", false, CoreMatchers.is(equalTo(fault.getInternalcode() == null)));
	        assertThat("Internal Message is not as expected", false, CoreMatchers.is(equalTo(fault.getInternalmessage() == null)));
		}

	}
}
